﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.Practices.Unity;
using Wyn.PMS.Common.Utils;
using Wyn.PMS.Entity.DataAccess;
using Wyn.PMS.Entity.Entities;
using Wyn.PMS.Entity.IDataAccess;

namespace Wyn.PMS.Common.NightAudit
{

    internal class OperationAnalysis
    {
        private static readonly IUnityContainer container = UnityContainerService.GetContainer();

        private Func<Order, bool> exp;

        private Func<Order, bool> noHourDayExp;

        internal void Total(HotelBizDay bizDay, IDictionary<string, decimal> rtRoomFeeAccounts, IList<Account> notRollAccounts, IList<RoomType> roomTypes, IList<NaOperationStatus> states, IList<Order> allOrders, IList<Order> rollAccountOrders)
        {
            IAnalysisSubjectRepository analysisSubjectRepository = container.Resolve<IAnalysisSubjectRepository>();

            INaOperationAnalysisRepository analysisRepository = container.Resolve<INaOperationAnalysisRepository>();

            IOvertimeDiscountRepository overtimeDiscountRepository = container.Resolve<IOvertimeDiscountRepository>();
            
            var transactionOptions = new System.Transactions.TransactionOptions();

            transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;
            
            var subjects = analysisSubjectRepository.BatchFind(bizDay.HotelID, a => a.IsValid);

            var checkInTypes = GetCheckInTypes();

            var guestSources = GetGuestSources();

            var channelInfos = GetChannelInfos(bizDay.HotelID);

            IList<NaOperationAnalysis> analysisList = new List<NaOperationAnalysis>();
            
            DateTime today = bizDay.BizDay;

            var validRoomCount = states.Sum(s => s.Count) - states.Sum(s => s.OOOCount);

            var osI = EnumHelper.GetCode(OrderStatus.I);
            
            exp = o => o.Status == osI || o.CheckInBizDay == today;

            string CIT_HR = EnumHelper.GetCode(CheckInType.HR), CIT_DR = EnumHelper.GetCode(CheckInType.DR);

            noHourDayExp =o =>(o.Status == osI || o.CheckInBizDay == today) && o.CheckInType != CIT_HR &&o.CheckInType != CIT_DR;

            string hotelId = bizDay.HotelID;
            
            DateTime lastMonthToday = bizDay.BizDay.AddMonths(-1);
            Expression<Func<NaOperationAnalysis, bool>> lastMonthExp = a => a.HotelID == hotelId && a.BizDay == lastMonthToday;
            
            DateTime lastYearToday = bizDay.BizDay.AddYears(-1);
            Expression<Func<NaOperationAnalysis, bool>> lastYearExp = a => a.HotelID == hotelId && a.BizDay == lastYearToday;
            
            DateTime yesterday = bizDay.BizDay.AddDays(-1);
            Expression<Func<NaOperationAnalysis, bool>> yesterdayExp = a => a.HotelID == hotelId && a.BizDay == yesterday;
            
            Expression<Func<OvertimeDiscount, bool>> discountExp = o => o.BizDay == today && o.HotelID == hotelId;
            
            IList<NaOperationAnalysis> lastMonthTodayAnalysisList = new List<NaOperationAnalysis>();
            IList<NaOperationAnalysis> lastYearTodayAnalysisList = new List<NaOperationAnalysis>();
            IList<NaOperationAnalysis> yesterdayAnalysisList = new List<NaOperationAnalysis>();
            IList<OvertimeDiscount> discounts = new List<OvertimeDiscount>();

            using (var scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required, transactionOptions))
            {
                lastMonthTodayAnalysisList = analysisRepository.BatchFind(bizDay.HotelID, lastMonthExp);

                lastYearTodayAnalysisList = analysisRepository.BatchFind(bizDay.HotelID, lastYearExp);

                yesterdayAnalysisList = analysisRepository.BatchFind(bizDay.HotelID, yesterdayExp);

                discounts = overtimeDiscountRepository.BatchFind(hotelId, discountExp);

                scope.Complete();
            }
            
            foreach (var item in subjects)
            {
                NaOperationAnalysis analysis = AnalysisSubject(item, bizDay, notRollAccounts, states, allOrders,discounts, validRoomCount,rollAccountOrders);
                
                FillOtherInfo(bizDay, yesterday, yesterdayAnalysisList,lastMonthTodayAnalysisList,lastYearTodayAnalysisList, analysis, item.Code);

                analysisList.Add(analysis);
            }
            
            foreach (var type in checkInTypes)
            {
                NaOperationAnalysis analysis = AnalysisCheckIntype(type, bizDay, notRollAccounts, allOrders, validRoomCount,rollAccountOrders);

                var CITAnalysisCode = GlobalConst.ANALYSIS_PREFIX_CHECKIN_TYPE + type.Key;
                
                FillOtherInfo(bizDay, yesterday, yesterdayAnalysisList, lastMonthTodayAnalysisList, lastYearTodayAnalysisList, analysis, CITAnalysisCode);

                analysisList.Add(analysis);
            }
            

            foreach (var source in guestSources)
            {
              
                NaOperationAnalysis analysis = AnalysisSource(source, bizDay, allOrders, notRollAccounts, validRoomCount, rollAccountOrders);

                var GSCAnalysisCode = GlobalConst.ANALYSIS_PREFIX_GSC + source.Key;

                FillOtherInfo(bizDay, yesterday, yesterdayAnalysisList, lastMonthTodayAnalysisList, lastYearTodayAnalysisList, analysis, GSCAnalysisCode);

                analysisList.Add(analysis);
            }
            
            foreach (var channel in channelInfos)
            {
                NaOperationAnalysis analysis = AnalysisChannel(channel, bizDay, notRollAccounts,allOrders,validRoomCount,rollAccountOrders);

                var CHAAnalysisCode = GlobalConst.ANALYSIS_PREFIX_CHANNEL + channel.ID.ToString();

                FillOtherInfo(bizDay, yesterday, yesterdayAnalysisList, lastMonthTodayAnalysisList,lastYearTodayAnalysisList, analysis, CHAAnalysisCode);

                analysisList.Add(analysis);
            }
            
            foreach (var roomtype in roomTypes)
            {
                NaOperationAnalysis analysis = AnalysisRoomType(roomtype, bizDay, states,allOrders);

                var RTAnalysisCode = GlobalConst.ANALYSIS_PREFIX_RT + roomtype.RoomTypeID;

                FillOtherInfo(bizDay, yesterday, yesterdayAnalysisList, lastMonthTodayAnalysisList, lastYearTodayAnalysisList, analysis, RTAnalysisCode);

                analysisList.Add(analysis);

                NaOperationAnalysis analysisInRoom = AnalysisRoomTypeInRoom(roomtype, bizDay, allOrders, notRollAccounts, rollAccountOrders);

                analysisInRoom.ValidTodayTotal = analysis.ValidTodayTotal;

                FillOtherInfo(bizDay, yesterday, yesterdayAnalysisList, lastMonthTodayAnalysisList, lastYearTodayAnalysisList, analysisInRoom, analysisInRoom.ItemCode);

                analysisList.Add(analysisInRoom);

                #region 未结 没鸟用
                /*

                NaOperationAnalysis analysisOk = AnalysisRoomTypeOK(roomtype, bizDay, inHotelAccountRoots);

                FillOtherInfo(bizDay, yesterday, yesterdayAnalysisList, lastMonthTodayAnalysisList, lastYearTodayAnalysisList, analysisOk, analysisOk.ItemCode);

                analysisList.Add(analysisOk);                
                
                */
                #endregion
            }
            
            if (bizDay.Status != EnumHelper.GetCode(NightAuditCode.Status.E)
                || (bizDay.Status == EnumHelper.GetCode(NightAuditCode.Status.E)
                && bizDay.Steping == (int)NightAuditCode.Steping.OperationAnalysis))
            {
                bizDay.Status = EnumHelper.GetCode(NightAuditCode.Status.I);

                analysisRepository.BatchInsert(hotelId, analysisList);
            }
        }

        private NaOperationAnalysis AnalysisSubject(AnalysisSubject item, HotelBizDay bizDay, IList<Account> notRollAccounts, IList<NaOperationStatus> states, IList<Order> orders, IList<OvertimeDiscount> discounts, int validRoomCount, IList<Order> rollOrders)
        {
            
            string hotelId = bizDay.HotelID;

            DateTime today = bizDay.BizDay;

            string osI= EnumHelper.GetCode(OrderStatus.I);
            
            var rsMonitor = CacheMonitor.GetInstance();

            var rooms = rsMonitor.GetCacheRooms(GlobalConst.DEFAULT_START_TIME,hotelId).Value;
            
            NaOperationAnalysis ananlysis = new NaOperationAnalysis();

            ananlysis.HotelID = bizDay.HotelID;

            ananlysis.BizDay = bizDay.BizDay;

            ananlysis.ItemCode = item.Code;

            ananlysis.ItemName = item.Name;

            ananlysis.ValidTodayTotal = validRoomCount;
            
            switch(item.Code)
            {
                case AnalysisSubjectCode.外宾数:
                    
                    var foreign = orders.Where(a => !string.IsNullOrEmpty(a.Country)
                                      && a.Country != GlobalConst.COUNTRY_中国
                                      && a.Country != GlobalConst.COUNTRY_台湾
                                      && a.Country != GlobalConst.COUNTRY_香港
                                      && a.Country != GlobalConst.COUNTRY_澳门)
                                      .ToList();

                    //ananlysis.TodayReceipts = SumReceipts(foreign,notRollAccounts,false);

                    ananlysis.TodayCount = foreign.Count(exp);

                    break;

                case AnalysisSubjectCode.内宾数:
                    var land = orders.Where(o => string.IsNullOrEmpty(o.Country)
                                      || o.Country == GlobalConst.COUNTRY_中国)
                                      .ToList();

                    //ananlysis.TodayReceipts = SumReceipts(land,notRollAccounts,false);

                    ananlysis.TodayCount = land.Count(exp);

                    break;

                case AnalysisSubjectCode.港澳台数:
                    var HK_MAC_CN = orders.Where(o => !string.IsNullOrEmpty(o.Country)
                                        && (o.Country == GlobalConst.COUNTRY_台湾
                                            || o.Country == GlobalConst.COUNTRY_香港
                                            || o.Country == GlobalConst.COUNTRY_澳门))
                                            .ToList();

                    //ananlysis.TodayReceipts = SumReceipts( HK_MAC_CN,notRollAccounts,false);

                    ananlysis.TodayCount = HK_MAC_CN.Count(exp);

                    break;

                case AnalysisSubjectCode.租客合计:

                    //ananlysis.TodayReceipts = SumReceipts(orders,notRollAccounts,false);

                    ananlysis.TodayCount = orders.Count(exp);

                    break;

                case AnalysisSubjectCode.当日租项:

                    ananlysis.TodayReceipts = notRollAccounts.Where(a=>a.LedgerCode==LedgerCode.半日租 || a.LedgerCode==LedgerCode.全日租).Sum(a => a.Balance);

                    ananlysis.TodayCount = notRollAccounts.Count(a => a.Balance>0 && ( a.LedgerCode == LedgerCode.半日租 || a.LedgerCode == LedgerCode.全日租));
                    
                    break;

                case AnalysisSubjectCode.全日租数:

                    ananlysis.TodayReceipts = notRollAccounts.Where(a=>a.LedgerCode==LedgerCode.全日租).Sum(a => a.Balance);

                    ananlysis.TodayCount = notRollAccounts.Count(a =>a.Balance>0 && a.LedgerCode == LedgerCode.全日租);
                    
                    break;
                case AnalysisSubjectCode.半日租数:

                    ananlysis.TodayReceipts = notRollAccounts.Where(a=>a.LedgerCode==LedgerCode.半日租).Sum(a => a.Balance);

                    ananlysis.TodayCount = notRollAccounts.Count(a =>a.Balance>0 && a.LedgerCode == LedgerCode.半日租);
                    
                    break;

                case AnalysisSubjectCode.减免房租:

                    ananlysis.TodayCount = discounts.Count;

                    ananlysis.TodayReceipts = discounts.Sum(d=>d.Money);

                    break;

                case AnalysisSubjectCode.标准房租:
                    
                    ananlysis.TodayReceipts = notRollAccounts.Where(a=>a.LedgerCode==LedgerCode.标准房租).Sum(a => a.Balance);

                    ananlysis.TodayCount = notRollAccounts.Count(a => a.LedgerCode == LedgerCode.标准房租);

                    break;

                case AnalysisSubjectCode.钟点会员:

                    var hours = orders.Where(a => a.CheckInType == EnumHelper.GetCode(CheckInType.HR)
                                                  && a.GuestSourceType == EnumHelper.GetCode(GuestSourceType.IM))
                                                  .ToList();

                    //ananlysis.TodayReceipts = SumReceipts(hours,notRollAccounts,false);

                    ananlysis.TodayCount = hours.Count(exp);

                    break;

                case AnalysisSubjectCode.白天会员:
                    var days = orders.Where(a => a.CheckInType == EnumHelper.GetCode(CheckInType.DR)
                                                 && a.GuestSourceType == EnumHelper.GetCode(GuestSourceType.IM))
                                                 .ToList();

                    //ananlysis.TodayReceipts = SumReceipts(days,notRollAccounts,false);

                    ananlysis.TodayCount = days.Count(exp);

                    break;

                case AnalysisSubjectCode.空房数:
                    ananlysis.TodayCount = rooms.Count(r => r.Status == EnumHelper.GetCode(RoomStatus.VC)
                                                            || r.Status == EnumHelper.GetCode(RoomStatus.VD)
                                                            || r.Status == EnumHelper.GetCode(RoomStatus.OK));
                    break;

                case AnalysisSubjectCode.占房数:
                    ananlysis.TodayCount = rooms.Count(r => r.Status == EnumHelper.GetCode(RoomStatus.OC)
                                                            || r.Status == EnumHelper.GetCode(RoomStatus.OD));
                    break;
                case AnalysisSubjectCode.维修房数:
                    ananlysis.TodayCount = states.Sum(s => s.RepairCount);
                    break;
                case AnalysisSubjectCode.自用房数:
                    ananlysis.TodayCount = orders.Count(o => o.CheckInType == EnumHelper.GetCode(CheckInType.SU) && (o.Status==osI || o.CheckInBizDay==today ));
                    break;
                case AnalysisSubjectCode.总房数:
                    ananlysis.TodayCount = states.Sum(s => s.Count);
                    break;
                case AnalysisSubjectCode.出租率:
                    BuildLettingRate(notRollAccounts, orders, validRoomCount, ananlysis);
                    break;
                case AnalysisSubjectCode.豁免数:
                    ananlysis.TodayCount =states.Sum(o=>o.OOOCount);
                    break;
                case AnalysisSubjectCode.预订抵达数:
                    ananlysis.TodayCount = states.Sum(s => s.ResvArrived);
                    break;
                case AnalysisSubjectCode.预订未抵达数:
                    ananlysis.TodayCount = states.Sum(s => s.NoShow);
                    break;
                case AnalysisSubjectCode.预订取消数:
                    ananlysis.TodayCount = states.Sum(s => s.ResvCancel);
                    break;
                case AnalysisSubjectCode.当日来店数:
                    //var todayIn = orders.Where(a =>a.CheckInBizDay == bizDay.BizDay);
                    //ananlysis.TodayReceipts = SumReceipts(todayIn,notRollAccounts,true);
                    ananlysis.TodayCount = orders.Count(a => a.CheckInBizDay == bizDay.BizDay);

                    break;
                case AnalysisSubjectCode.当日离店数:
                    //var todayOut = orders.Where(a =>a.CheckOutBizDay.HasValue&& a.CheckOutBizDay.Value == today);

                    //ananlysis.TodayReceipts = SumReceipts(todayOut,notRollAccounts,true);

                    ananlysis.TodayCount = orders.Count(a => a.CheckOutBizDay.HasValue && a.CheckOutBizDay.Value == today);

                    break;
                case AnalysisSubjectCode.折扣房数:

                    IList<Order> disOrders = GetDiscountOrders(orders,today,true);
                    
                    //ananlysis.TodayReceipts = SumReceipts(disOrders, notRollAccounts, true);

                    ananlysis.TodayCount = disOrders.Count(exp);
                    break;

                case AnalysisSubjectCode.全价房数:

                    IList<Order> notDisOrders = GetDiscountOrders(orders,today,false);

                    //ananlysis.TodayReceipts = SumReceipts(notDisOrders, notRollAccounts, true);

                    ananlysis.TodayCount = notDisOrders.Count(exp);
                    break;
                case AnalysisSubjectCode.预抵数:
                    ananlysis.TodayCount = states.Sum(s => s.WillArriveCount);
                    break;

                case AnalysisSubjectCode.预离数:
                    ananlysis.TodayCount = states.Sum(s => s.WillLeaveCount);
                    break;
                case AnalysisSubjectCode.预留数:
                    ananlysis.TodayCount = states.Sum(s => s.ResvAssigned);
                    break;

                case AnalysisSubjectCode.当日预订数:
                    //ananlysis.TodayReceipts = 
                    ananlysis.TodayCount = states.Sum(s => s.ResvCount);
                    break;

                case AnalysisSubjectCode.提前离店数:
                    ananlysis.TodayCount = states.Sum(s => s.EarlyCheckOut);
                    break;

                case AnalysisSubjectCode.挂账金额:

                    ananlysis.TodayReceipts = notRollAccounts.Where(a=>a.LedgerCode==LedgerCode.挂帐).Sum(a => a.Balance);

                    ananlysis.TodayCount = notRollAccounts.Count(a => a.LedgerCode == LedgerCode.挂帐);

                    break;

                case AnalysisSubjectCode.该离未离数:
                    //统计续住
                    break;
                case AnalysisSubjectCode.积分兑换:

                    Func<Order,bool> pointExchangeExp = a => a.ActivityCode == GlobalConst.POINT_EXCHANGE;
                    
                    var pointExchange = rollOrders.Where(pointExchangeExp).ToList();

                    var exchangeOrders = orders.Where(pointExchangeExp).ToList();

                    ananlysis.TodayReceipts = SumReceipts(pointExchange, notRollAccounts);

                    ananlysis.TodayCount = exchangeOrders.Count(noHourDayExp);

                    break;
                case AnalysisSubjectCode.招待房:
                    Func<Order, bool> receptSelfExp = a =>a.ActivityCode == GlobalConst.POINT_RECEPT_SELF;

                    var receptSelf = rollOrders.Where(receptSelfExp).ToList();

                    var selfOrders = orders.Where(receptSelfExp).ToList();

                    ananlysis.TodayReceipts = SumReceipts(receptSelf, notRollAccounts);

                    ananlysis.TodayCount = selfOrders.Count(noHourDayExp);

                    break;
            }

            return ananlysis;
        }

        private NaOperationAnalysis AnalysisCheckIntype(KeyValuePair<string, string> type, HotelBizDay bizDay, IList<Account> notRollAccounts, IList<Order> allOrders, int validRoomCount, IList<Order> rollAccountOrders)
        {
            NaOperationAnalysis ananlysis = new NaOperationAnalysis();

            ananlysis.HotelID = bizDay.HotelID;

            ananlysis.BizDay = bizDay.BizDay;

            ananlysis.ItemCode = GlobalConst.ANALYSIS_PREFIX_CHECKIN_TYPE + type.Key;

            ananlysis.ItemName = type.Value;

            ananlysis.ValidTodayTotal = validRoomCount;

            var orders = allOrders.Where(a => a.CheckInType == type.Key).ToList();

            if (notRollAccounts != null && notRollAccounts.Any())
            {
                ananlysis.TodayReceipts = notRollAccounts.Where(a => a.CheckInType == type.Key
                                                                     && a.LedgerParentCode == LedgerCode.客房收入
                                                                     && a.LedgerCode != LedgerCode.全日租
                                                                     && a.LedgerCode != LedgerCode.半日租
                                                                     && !a.IsStrike).Sum(a => a.Balance);
            }

            ananlysis.TodayCount = orders.Count(exp);

            return ananlysis;
        }

        private NaOperationAnalysis AnalysisSource(KeyValuePair<string, string> source, HotelBizDay bizDay, IList<Order> allOrders, IList<Account> notRollAccounts, int validRoomCount, IList<Order> rollAccountOrders)
        {
            NaOperationAnalysis ananlysis = new NaOperationAnalysis();

            ananlysis.HotelID = bizDay.HotelID;

            ananlysis.BizDay = bizDay.BizDay;

            ananlysis.ItemCode = GlobalConst.ANALYSIS_PREFIX_GSC + source.Key;

            ananlysis.ItemName = source.Value;

            ananlysis.ValidTodayTotal = validRoomCount;

            var orders = allOrders.Where(a => a.GuestSourceType == source.Key
                                              && a.CheckInType != EnumHelper.GetCode(CheckInType.DR)
                                              && a.CheckInType != EnumHelper.GetCode(CheckInType.HR)).ToList();

            var rollOrders = rollAccountOrders.Where(a => a.GuestSourceType == source.Key).ToList();

            ananlysis.TodayReceipts = SumReceipts(rollOrders, notRollAccounts);

            ananlysis.TodayCount = orders.Count(noHourDayExp);

            return ananlysis;
        }

        private NaOperationAnalysis AnalysisChannel(ChannelInfo channel, HotelBizDay bizDay, IList<Account> notRollAccounts, IList<Order> allOrders, int validRoomCount, IList<Order> rollAccountOrders)
        {
            NaOperationAnalysis ananlysis = new NaOperationAnalysis();

            ananlysis.HotelID = bizDay.HotelID;

            ananlysis.BizDay = bizDay.BizDay;

            ananlysis.ItemCode = GlobalConst.ANALYSIS_PREFIX_CHANNEL + channel.ID.ToString();

            ananlysis.ItemName = channel.Name;

            ananlysis.ValidTodayTotal = validRoomCount;

            var orders = allOrders.Where(a => a.ChannelID == channel.ID
                                              && a.CheckInType != EnumHelper.GetCode(CheckInType.DR)
                                              && a.CheckInType != EnumHelper.GetCode(CheckInType.HR)).ToList();

            var rollOrders = rollAccountOrders.Where(a => a.ChannelID == channel.ID).ToList();

            ananlysis.TodayReceipts = SumReceipts(rollOrders, notRollAccounts);

            ananlysis.TodayCount = orders.Count(noHourDayExp);

            return ananlysis;
        }

        private NaOperationAnalysis AnalysisRoomType(RoomType roomtype, HotelBizDay bizDay, IList<NaOperationStatus> states, IList<Order> allOrders)
        {
            NaOperationAnalysis ananlysis = new NaOperationAnalysis();

            ananlysis.HotelID = bizDay.HotelID;

            ananlysis.BizDay = bizDay.BizDay;

            ananlysis.ItemCode = GlobalConst.ANALYSIS_PREFIX_RT + roomtype.RoomTypeID;

            ananlysis.ItemName = roomtype.RoomTypeName;

            var state = states.FirstOrDefault(s => s.RoomTypeID == roomtype.RoomTypeID);

            if(state != null)
            {
                ananlysis.ValidTodayTotal = state.Count - state.OOOCount;

                ananlysis.TodayReceipts = state.TodayRoomReceipts;
            }

            var osI = EnumHelper.GetCode(OrderStatus.I);

            ananlysis.TodayCount = allOrders.Count(a => a.RoomTypeID == roomtype.RoomTypeID
                                                        && (a.Status == osI || a.CheckInBizDay == bizDay.BizDay)
                                                        && a.CheckInType!=EnumHelper.GetCode(CheckInType.DR)
                                                        && a.CheckInType!=EnumHelper.GetCode(CheckInType.HR));

            return ananlysis;
        }

      
        private NaOperationAnalysis AnalysisRoomTypeInRoom(RoomType roomtype, HotelBizDay bizDay, IList<Order> allOrders, IList<Account> notRollAccounts,IList<Order> rollAccountOrders)
        {
            NaOperationAnalysis ananlysis = new NaOperationAnalysis();

            ananlysis.HotelID = bizDay.HotelID;

            ananlysis.BizDay = bizDay.BizDay;

            ananlysis.ItemCode = GlobalConst.ANALYSIS_PREFIX_RT_IN_ROOM + roomtype.RoomTypeID;

            ananlysis.ItemName = roomtype.RoomTypeName + GlobalConst.ANALYSIS_PREFIX_RT_IN_ROOM_NAME;

            var orders = allOrders.Where(a => a.RoomTypeID == roomtype.RoomTypeID
                                              && a.Status == EnumHelper.GetCode(OrderStatus.I)
                                              && a.CheckInType != EnumHelper.GetCode(CheckInType.DR)
                                              && a.CheckInType != EnumHelper.GetCode(CheckInType.HR))
                                              .ToList();

            IList<Order> rollOrdes = rollAccountOrders.Where(a => a.RoomTypeID == roomtype.RoomTypeID
                                                                  && a.Status == EnumHelper.GetCode(OrderStatus.I))
                                                                  .ToList();

            ananlysis.TodayReceipts = SumReceipts(rollOrdes, notRollAccounts);

            ananlysis.TodayCount = orders.Count();

            return ananlysis;
        }

        private void FillOtherInfo(HotelBizDay bizDay, DateTime yesterday, IList<NaOperationAnalysis> yesterdayAnalysisList, IList<NaOperationAnalysis> lastMonthTodayAnalysisList, IList<NaOperationAnalysis> lastYearTodayAnalysisList, NaOperationAnalysis analysis, string code)
        {
          
            var yesterdayAnalysis = (yesterdayAnalysisList != null && yesterdayAnalysisList.Any())
                                        ? yesterdayAnalysisList.FirstOrDefault(a => a.ItemCode == code)
                                        : null;

            if (yesterdayAnalysis != null && yesterday.Month == bizDay.BizDay.Month)
            {
                analysis.MonthReceipts = analysis.TodayReceipts + yesterdayAnalysis.MonthReceipts;

                analysis.MonthCount = analysis.TodayCount + yesterdayAnalysis.MonthCount;

                analysis.ValidMonthTotal = analysis.ValidTodayTotal + yesterdayAnalysis.ValidMonthTotal;

            }
            else
            {
                analysis.MonthReceipts = analysis.TodayReceipts;

                analysis.MonthCount = analysis.TodayCount;

                analysis.ValidMonthTotal = analysis.ValidTodayTotal;
            }

       
            if (yesterdayAnalysis != null && yesterday.Year == bizDay.BizDay.Year)
            {
                analysis.YearReceipts = analysis.TodayReceipts + yesterdayAnalysis.YearReceipts;

                analysis.YearCount = analysis.TodayCount + yesterdayAnalysis.YearCount;

                analysis.ValidYearTotal = analysis.ValidTodayTotal + yesterdayAnalysis.ValidYearTotal;

            }
            else
            {
                analysis.YearReceipts = analysis.TodayReceipts;

                analysis.YearCount = analysis.TodayCount;

                analysis.ValidYearTotal = analysis.ValidTodayTotal;
            }

         
            if (lastMonthTodayAnalysisList != null && lastMonthTodayAnalysisList.Any())
            {
                var lastMonthAnalysis = lastMonthTodayAnalysisList.FirstOrDefault(a => a.ItemCode == code);

                if (lastMonthAnalysis != null)
                {
                    analysis.LastMonthTodayReceipts = lastMonthAnalysis.TodayReceipts;

                    analysis.LastMonthTodayCount = lastMonthAnalysis.TodayCount;

                    analysis.ValidLastMonthTodayTotal = lastMonthAnalysis.ValidTodayTotal;
                }
            }

           
            if (lastYearTodayAnalysisList != null && lastYearTodayAnalysisList.Any())
            {
                var lastYearAnalysis = lastYearTodayAnalysisList.FirstOrDefault(a => a.ItemCode == code);

                if (lastYearAnalysis != null)
                {
                    analysis.LastYearMonthReceipts = lastYearAnalysis.MonthReceipts;

                    analysis.LastYearMonthCount = lastYearAnalysis.MonthCount;

                    analysis.LastYearReceipts = lastYearAnalysis.YearReceipts;

                    analysis.LastYearCount = lastYearAnalysis.YearCount;

                    analysis.ValidLastYearMonthTotal = lastYearAnalysis.ValidMonthTotal;

                    analysis.ValidLastYearTotal = lastYearAnalysis.ValidYearTotal;
                }
            }
            
        }
        
        private decimal SumReceipts(IEnumerable<Order> orders, IList<Account> notRollAccounts)
        {
            IEnumerable<string> orderIds = orders.Select(o => o.OrderID);

            decimal receipts = 0;

            string CIT_HR = EnumHelper.GetCode(CheckInType.HR),CIT_DR=EnumHelper.GetCode(CheckInType.DR);

            if (notRollAccounts != null && notRollAccounts.Any())
            {
                receipts = notRollAccounts
                    .Where(a => orderIds.Contains(a.CreateOrderID)
                                && (a.LedgerCode==LedgerCode.标准房租
                                   || a.LedgerCode == LedgerCode.加床)
                                && a.CheckInType != CIT_HR
                                && a.CheckInType != CIT_DR
                                && !a.IsStrike)
                    .Sum(a => a.Balance);
            }

            return receipts;
        }
        
        private IList<ChannelInfo> GetChannelInfos(string hotelId)
        {
            IChannelInfoRepository repository = container.Resolve<IChannelInfoRepository>();

            Expression<Func<ChannelInfo, bool>> channelExp = a => a.IsValid;

            return repository.BatchFind(hotelId, channelExp);
        }

        private IDictionary<string, string> GetGuestSources()
        {
            var guestSources = BizCodeCache
                .GetBizCode(GlobalConst.ROOT_HOTEL_ID, CodeHelper.GetParentKey(typeof(GuestSourceType).Name))
                .Where(k => k.IsValid)
                .ToDictionary(k => k.KeyValue, k => k.KeyName);

            return guestSources;
            #region
            //IDictionary<string, string> guestSources = new Dictionary<string, string>();

            //guestSources.Add(EnumHelper.GetCode(GuestSourceType.AM), "中介协议");
            //guestSources.Add(EnumHelper.GetCode(GuestSourceType.CM), "公司会员");
            //guestSources.Add(EnumHelper.GetCode(GuestSourceType.GP), "团队");
            //guestSources.Add(EnumHelper.GetCode(GuestSourceType.IM), "个人会员");
            //guestSources.Add(EnumHelper.GetCode(GuestSourceType.LP), "长包");
            //guestSources.Add(EnumHelper.GetCode(GuestSourceType.WI), "上门散客");

            //return guestSources;
            #endregion
        }

        public IDictionary<string, string> GetCheckInTypes()
        {
            //IDictionary<string,string> checkInTypes = new Dictionary<string, string>();

            var checkInTypes = BizCodeCache
                .GetBizCode(GlobalConst.ROOT_HOTEL_ID,CodeHelper.GetParentKey(typeof (CheckInType).Name))
                .Where(k => k.IsValid)
                .ToDictionary(k => k.KeyValue, k => k.KeyName);

            return checkInTypes;
            #region
            //TODO 入住类型 维也纳 夜审操作分析
            //checkInTypes.Add(EnumHelper.GetCode(CheckInType.NS), "标准房");
            //checkInTypes.Add(EnumHelper.GetCode(CheckInType.DR), "白天房");
            //checkInTypes.Add(EnumHelper.GetCode(CheckInType.HR), "钟点房");
            //checkInTypes.Add(EnumHelper.GetCode(CheckInType.SU), "自用房");
            //checkInTypes.Add(EnumHelper.GetCode(CheckInType.FR), "免费房");
            //checkInTypes.Add(EnumHelper.GetCode(CheckInType.MF), "误机客");

            //return checkInTypes;
            #endregion
        }

        private static void BuildLettingRate(IList<Account> notRollAccounts, IList<Order> orders, int validRoomCount, NaOperationAnalysis ananlysis)
        {
            var NsCount = orders.Count(a => a.CheckInType == EnumHelper.GetCode(CheckInType.NS));

            var HrCount = orders.Count(a => a.CheckInType == EnumHelper.GetCode(CheckInType.HR));

            var DrCount = orders.Count(a => a.CheckInType == EnumHelper.GetCode(CheckInType.DR));

            var SuCount = orders.Count(a => a.CheckInType == EnumHelper.GetCode(CheckInType.SU));

            var FrCount = orders.Count(a => a.CheckInType == EnumHelper.GetCode(CheckInType.FR));

            var ExFullCount = notRollAccounts.Count(k => k.LedgerCode == LedgerCode.全日租);

            var ExHalfCount = notRollAccounts.Count(k => k.LedgerCode == LedgerCode.半日租);

            var fp = FormulaProvider.Instance;

            var formula = fp.GetFormula(FormulaProvider.AvgRoomPrice);

            if (validRoomCount > 0)
            {
                ananlysis.TodayReceipts = Math.Round((decimal)(
                                                               ((NsCount / formula.CheckInType_NS
                                                                 + FrCount / formula.CheckInType_FR
                                                                 + HrCount / formula.CheckInType_HR
                                                                 + DrCount / formula.CheckInType_DR
                                                                 + SuCount / formula.CheckInType_SU
                                                                 + ExFullCount / formula.Ledger_ExtraFullDay
                                                                 + ExHalfCount / formula.Ledger_ExtraHalfDay)
                                                                / validRoomCount) * 100), 2);
            }

            ananlysis.TodayCount = NsCount + FrCount + HrCount + DrCount + SuCount + ExFullCount + ExHalfCount / 2;
        }

        private IList<Order> GetDiscountOrders(IList<Order> orders,DateTime today,bool isDiscount)
        {
            IList<Order> disOrders = new List<Order>();

            IList<Order> notDisOrders = new List<Order>();

            foreach (var order in orders)
            {
                if (order.PriceDetail != null && order.PriceDetail.Count > 0)
                {
                    var price = order.PriceDetail.FirstOrDefault(b => b.BizDay == today) ??
                                order.PriceDetail.FirstOrDefault();

                    if (price != null)
                    {
                        if (price.Price != price.NormalPrice)
                        {
                            disOrders.Add(order);
                        }
                        else
                        {
                            notDisOrders.Add(order);
                        }
                    }
                    else
                    {
                        notDisOrders.Add(order);
                    }
                }
            }

            return isDiscount?disOrders:notDisOrders;
        }
        
    }
}
